import { Node, TiledMap, UITransform, v2, v3, Vec3 } from 'cc';
import { app } from 'db://app-game/core/app';
import { ecs } from 'db://app-game/libs/ecs/ECS';
import { AStar } from 'db://app-game/libs/math/AStar/AStar';
import { Graph } from 'db://app-game/libs/math/graph/Graph';
import { GameEvent } from '../../../../common/config/GameEvent';
import { StaticCreature } from '../../static-creature/StaticCreature';
import { LevelMap } from '../LevelMap';
import { MapBaseInfo, MapIndex } from '../LevelMap.type';
import { LevelMapModelComp } from '../model/LevelMapModelComp';
import { LevelMapModelRenderComp } from '../model/LevelMapRenderModelComp';
import { ECSEntity } from 'db://app-game/libs/ecs/ECSEntity';

/** 地图渲染系统 */
@ecs.register('MapRender')
export class MapRenderSystem
  extends ecs.ComblockSystem
  implements ecs.IEntityEnterSystem, ecs.ISystemUpdate
{
  filter(): ecs.IMatcher {
    return ecs.allOf(LevelMapModelComp, LevelMapModelRenderComp);
  }
  entityEnter(levelMap: LevelMap): void {
    let lmmr = levelMap.get(LevelMapModelRenderComp);
    this.renderMap2(levelMap).then(() => {
      // 7.2更新A星网络地图信息
      this.resetAStarMap(levelMap);
      // 7.3通知地图更新完成
      app.message.dispatchEvent(GameEvent.MapUpdateSuccess);
      lmmr.onRenderFinish = true;
    });
  }
  update(levelMap: LevelMap, dt: number): void {
    // // 1.获取数据层组件和业务层组件信息
    // let { chunkMapWidth, chunkMapHeight, maxRow, maxCol } = levelMap.LevelMapModel;
    // let lmmr = levelMap.get(LevelMapModelRenderComp);
    // // 2.更新时间信息
    // lmmr.time += dt;
    // // 3.查看渲染目标是否存在
    // if (!lmmr.target) return;
    // // 4.获取渲染中心位置
    // const centerPos = this.getCenterPos(levelMap.mapNode, lmmr.target);
    // // 5.判断是否需要加载新的地图
    // const centerMapIndex = this.verifyRender(levelMap, centerPos, lmmr.currentMapIndex);
    // if (!centerMapIndex) return;
    // lmmr.currentMapIndex = centerMapIndex;
    // // 6.获取需要渲染的地图和卸载的地图
    // const { mapRenderMap, resourcesToLoad, resourcesToUnload } = this.getLoadAndDeletedMap(
    //   levelMap,
    //   centerMapIndex,
    //   lmmr.currentMap
    // );
    // lmmr.currentMap = mapRenderMap;
    // // 7.渲染地图
    // this.renderMap(resourcesToLoad, levelMap).then(() => {
    //   // 7.1 卸载地图
    //   this.unloadMap(resourcesToUnload, levelMap);
    //   // 7.2更新A星网络地图信息
    //   this.resetAStarMap(levelMap);
    //   // 7.3通知地图更新完成
    //   app.message.dispatchEvent(GameEvent.MapUpdateSuccess);
    //   lmmr.onRenderFinish = true;
    // });
  }

  /** 获取渲染中心位置 */
  getCenterPos(levelMapNode: Node, target: Node | Vec3) {
    let centerPos;
    if (target instanceof Node) {
      let wPos = target.getComponent(UITransform).convertToWorldSpaceAR(v3(0, 0, 0));

      let nPos = levelMapNode.getComponent(UITransform).convertToNodeSpaceAR(wPos);
      centerPos = nPos;
    } else {
      centerPos = target;
    }

    return centerPos;
  }

  /** 校验是否重新渲染 */
  verifyRender(levelMap: LevelMap, pos: Vec3, currentMapIndex: MapIndex): MapIndex | false {
    const mapIndex = levelMap.computedMapIndex(pos, v3(0, 0));
    // 1.找不到地图直接判断为false
    if (!mapIndex) return false;
    if (mapIndex.row === currentMapIndex.row && mapIndex.col === currentMapIndex.col) return false;
    return mapIndex;
  }

  /** 获取需要加载和卸载的地图 */
  getLoadAndDeletedMap(
    levelMap: LevelMap,
    centerMapIndex: MapIndex,
    currentMap: Map<string, MapBaseInfo>
  ): {
    mapRenderMap: Map<string, MapBaseInfo>;
    resourcesToLoad: MapBaseInfo[];
    resourcesToUnload: MapBaseInfo[];
  } {
    let { chunkMapWidth, chunkMapHeight, maxRow, maxCol } = levelMap.LevelMapModel;
    const row = centerMapIndex.row;
    const col = centerMapIndex.col;

    let mapRenderMap = new Map([[`${row}-${col}`, levelMap.getMapInfo({ row, col })]]);
    let resourcesToUnload = [];
    let resourcesToLoad = [];
    let width = 3 * chunkMapWidth;
    let height = 3 * chunkMapHeight;

    // top
    if (row > 0) {
      const mapIndex = { row: row - 1, col };
      mapRenderMap.set(`${row - 1}-${col}`, levelMap.getMapInfo(mapIndex));
    } else {
      // 如果没有上面则地图高度减少1000
      height -= chunkMapHeight;
    }

    // bottom
    if (row < maxRow) {
      const mapIndex = { row: row + 1, col };
      mapRenderMap.set(`${row + 1}-${col}`, levelMap.getMapInfo(mapIndex));
    } else {
      // 如果没有上面则地图高度减少1000
      height -= chunkMapHeight;
    }

    // left
    if (col > 0) {
      const mapIndex = { row, col: col - 1 };
      mapRenderMap.set(`${row}-${col - 1}`, levelMap.getMapInfo(mapIndex));
    } else {
      width -= chunkMapWidth;
    }

    // right
    if (col < maxCol) {
      const mapIndex = { row, col: col + 1 };
      mapRenderMap.set(`${row}-${col + 1}`, levelMap.getMapInfo(mapIndex));
    } else {
      width -= chunkMapWidth;
    }

    // top left
    if (row > 0 && col > 0) {
      const mapIndex = { row: row - 1, col: col - 1 };
      mapRenderMap.set(`${row - 1}-${col - 1}`, levelMap.getMapInfo(mapIndex));
    }

    // top right
    if (row > 0 && col < maxCol) {
      const mapIndex = { row: row - 1, col: col + 1 };
      mapRenderMap.set(`${row - 1}-${col + 1}`, levelMap.getMapInfo(mapIndex));
    }

    // bottom left
    if (row < maxRow && col > 0) {
      const mapIndex = { row: row + 1, col: col - 1 };
      mapRenderMap.set(`${row + 1}-${col - 1}`, levelMap.getMapInfo(mapIndex));
    }

    // bottom right
    if (row < maxRow && col < maxCol) {
      const mapIndex = { row: row + 1, col: col + 1 };
      mapRenderMap.set(`${row + 1}-${col + 1}`, levelMap.getMapInfo(mapIndex));
    }

    // 1.上次渲染地图集合
    currentMap.forEach((value: MapBaseInfo, mapId: string) => {
      if (!mapRenderMap.has(mapId)) {
        resourcesToUnload.push(currentMap.get(mapId));
      }
    });
    // 2.本次渲染地图集合
    mapRenderMap.forEach((value: MapBaseInfo, mapId: string) => {
      if (!currentMap.has(mapId)) {
        resourcesToLoad.push(mapRenderMap.get(mapId));
      }
    });

    return {
      mapRenderMap,
      resourcesToUnload: resourcesToUnload,
      resourcesToLoad: resourcesToLoad,
    };
  }

  /** 渲染地图 */
  async renderMap(resourcesToLoad: MapBaseInfo[], levelMap: LevelMap) {
    const { chunkMapWidth, chunkMapHeight, initCol, initRow } = levelMap.LevelMapModel;
    const lmmr = levelMap.LevelMapModelRender;

    for (let i = 0; i < resourcesToLoad.length; i++) {
      if (lmmr.unloadMapPool.has(resourcesToLoad[i].id)) {
        lmmr.unloadMapPool.delete(resourcesToLoad[i].id);
        continue;
      }
      // 1.创建地图节点
      const { row, col } = resourcesToLoad[i];
      const node = await levelMap.createMapNode(row, col);
      node.name = `${row}-${col}-map`;

      // 2.设置地图位置
      const mapX = (col - initCol) * chunkMapWidth;
      const mapY = -(row - initRow) * chunkMapHeight;
      node.setPosition(mapX, mapY);

      // 3.设置地图父级节点
      node.parent = levelMap.mapNode;
      const tiledMap = node.getComponent(TiledMap);
      if (lmmr.currentMap.has(`${row}-${col}`)) {
        const mapBaseInfo = lmmr.currentMap.get(`${row}-${col}`);
        mapBaseInfo.tiledMap = tiledMap;
        lmmr.currentMap.set(`${row}-${col}`, mapBaseInfo);
      }
      // 4.添加静态障碍物渲染
      this.obstacleRender(tiledMap, resourcesToLoad[i], levelMap);

      // 5.添加静态障碍物
      this.objectObstacleRender(tiledMap, resourcesToLoad[i], levelMap);
    }
  }

  /** 渲染地图2 */
  async renderMap2(levelMap: LevelMap) {
    const { chunkMapWidth, chunkMapHeight, initCol, initRow, mapTable } = levelMap.LevelMapModel;
    let lmmr = levelMap.LevelMapModelRender;
    for (let row = 0; row < mapTable.length; row++) {
      for (let col = 0; col < mapTable[row].length; col++) {
        const mapIndex: MapIndex = { row, col };
        const mapInfo = levelMap.getMapInfo(mapIndex);
        const node = await levelMap.createMapNode(mapIndex.row, mapIndex.col);
        node.name = `${row}-${col}-map`;

        // 2.设置地图位置
        const mapX = (col - initCol) * chunkMapWidth;
        const mapY = -(row - initRow) * chunkMapHeight;
        node.setPosition(mapX, mapY);

        // 3.设置地图父级节点
        node.parent = levelMap.mapNode;
        const tiledMap = node.getComponent(TiledMap);
        mapInfo.tiledMap = tiledMap;
        lmmr.currentMap.set(`${row}-${col}`, mapInfo);
        // 4.添加静态障碍物渲染
        this.obstacleRender(tiledMap, mapInfo, levelMap);

        // 5.添加静态障碍物
        this.objectObstacleRender(tiledMap, mapInfo, levelMap);
      }
    }
  }

  /** 卸载地图 */
  unloadMap(resourcesToUnload: MapBaseInfo[], levelMap: LevelMap) {
    const lmmr = levelMap.LevelMapModelRender;

    resourcesToUnload.forEach(mapBaseInfo => {
      const mapName = `${mapBaseInfo.row}-${mapBaseInfo.col}-map`;
      const child = levelMap.mapNode.children.find((child: Node) => mapName === child.name);
      if (child) {
        const params = {
          ...mapBaseInfo,
          node: child,
          unloadTime: lmmr.time,
        };
        lmmr.unloadMapPool.set(mapBaseInfo.id, params);
      }
    });
    const unloadMapPool = Array.from(lmmr.unloadMapPool.values());
    for (let i = 0; i < unloadMapPool.length - 1; i++) {
      if (lmmr.time - unloadMapPool[i].unloadTime > lmmr.unloadCacheTime) {
        unloadMapPool[i].node.destroy();
        lmmr.unloadMapPool.delete(unloadMapPool[i].id);
      }
    }
  }

  /** 障碍物渲染 */
  obstacleRender(tiledMap: TiledMap, mapInfo: MapBaseInfo, levelMap: LevelMap) {
    const lmmr = levelMap.LevelMapModelRender;
    // 1.如果已经加载过了就不加载了
    if (lmmr.obstacleMap.has(mapInfo.id)) return;
    // 2.获取地图障碍物层级
    const layerObstacle = tiledMap.getLayer('obstacle');
    if (!layerObstacle) return;

    // 3.获取障碍物基础信息
    const obstacleSize = layerObstacle.getLayerSize();
    let mapSize = layerObstacle.getMapTileSize();
    const obstaclesMap = new Map();
    // 4.遍历瓷砖每一块
    for (let x = 0; x < obstacleSize.width; x++) {
      for (let y = 0; y < obstacleSize.height; y++) {
        // 3.1判断当前块是否有属性
        const tiled = layerObstacle.getTiledTileAt(x, y, true);
        // 3.2判断是否有grid
        if (tiled.grid === 0) continue;
        // 3.3配置障碍物基础信息
        const pos = v2(
          mapInfo.minX + mapSize.width * x + mapSize.width / 2,
          mapInfo.maxY - mapSize.height * y - mapSize.height / 2
        );
        const obstacleInfo = {
          id: `${mapInfo.id}-${x}-${y}`,
          pos,
          x,
          y,
          minX: pos.x - mapSize.width / 2,
          maxX: pos.x + mapSize.width / 2,
          minY: pos.y - mapSize.height / 2,
          maxY: pos.y + mapSize.height / 2,
        };
        obstaclesMap.set(`${x}-${y}`, obstacleInfo);
      }
    }
    lmmr.obstacleMap.set(`${mapInfo.id}`, obstaclesMap);
  }

  /** 添加对象 */
  objectObstacleRender(tiledMap: TiledMap, mapInfo: MapBaseInfo, levelMap: LevelMap) {
    const lmmr = levelMap.LevelMapModelRender;
    // 生物加载过的过滤
    if (lmmr.staticCreatureMap.has(mapInfo.id)) return;

    // 1.获取静态生物点位
    let staticCreatureGroup = tiledMap.getObjectGroup('staticCreature');
    if (!staticCreatureGroup) return;
    let staticCreatureObjects = staticCreatureGroup.getObjects();

    // 2.创建静态生物预制体
    for (let i = 0; i < staticCreatureObjects.length; i++) {
      // 2.1获取静态生物信息
      let staticCreatureObject = staticCreatureObjects[i] as any;

      // 2.2创建静态生物实体
      const staticCreature = ecs.getEntity<StaticCreature>(StaticCreature);
      const pos = v3(
        mapInfo.minX + staticCreatureObject.offset.x,
        mapInfo.maxY - staticCreatureObject.offset.y
      );
      staticCreature.StaticModel.id = staticCreatureObject.obstacleType as number;
      staticCreature.load(levelMap.staticCreatureFactoryNode, pos);

      // 2.3添加静态生物信息
      if (lmmr.staticCreatureMap.has(mapInfo.id)) {
        const staticCreatures = lmmr.staticCreatureMap.get(mapInfo.id);
        staticCreatures.push(staticCreature);
        lmmr.staticCreatureMap.set(`${mapInfo.id}`, staticCreatures);
      } else {
        lmmr.staticCreatureMap.set(`${mapInfo.id}`, [staticCreature]);
      }
    }
  }

  /** 重置A星地图 */
  resetAStarMap(levelMap: LevelMap) {
    const lmmr = levelMap.LevelMapModelRender;
    const { tileColNumber, tileRowNumber } = levelMap.LevelMapModel;

    const { matrix: tiledMapList, mapKeys } = this.mapToValueMatrix(lmmr.currentMap);
    const firstMap = mapKeys[0][0];
    const tileOffsetX = parseInt(firstMap.split('-')[0]) * tileColNumber;
    const tileOffsetY = parseInt(firstMap.split('-')[1]) * tileRowNumber;
    const graph = new Graph(
      tiledMapList,
      'obstacle',
      { diagonal: true },
      { x: tileOffsetX, y: tileOffsetY }
    );
    lmmr.graph = graph;
  }

  /** 将map转换为二维数组 */
  mapToValueMatrix(map: Map<string, MapBaseInfo>): { matrix: TiledMap[][]; mapKeys: string[][] } {
    let maxRow = -1;
    let maxCol = -1;

    // 确定最大行和列
    for (const key of map.keys()) {
      const [xStr, yStr] = key.split('-');
      const x = parseInt(xStr, 10);
      const y = parseInt(yStr, 10);
      if (x > maxRow) maxRow = x;
      if (y > maxCol) maxCol = y;
    }

    // 生成二维数组并填充值
    const matrix = [];
    const mapKeys = [];
    for (let x = 0; x <= maxRow; x++) {
      const row = [];
      const mapKeyRow = [];
      for (let y = 0; y <= maxCol; y++) {
        const key = `${x}-${y}`;
        row.push(map.get(key)?.tiledMap); // 不存在则为undefined
        mapKeyRow.push(key);
      }
      matrix.push(row);
      mapKeys.push(mapKeyRow);
    }

    return { matrix, mapKeys };
  }
}
